// Custom sorting plugin
(function($) {
    $.fn.quicksand = function (collection, customOptions) {     
    var options = {
        duration: 750,
        easing: 'swing',
        attribute: 'data-id', // attribute to recognize same items within source and dest
        adjustHeight: 'auto', // 'dynamic' animates height during shuffling (slow), 'auto' adjusts it before or after the animation, false leaves height constant
        useScaling: false, // disable it if you're not using scaling effect or want to improve performance
        enhancement: function(c) {}, // Visual enhacement (eg. font replacement) function for cloned elements
        selector: '> *',
        dx: 0,
        dy: 0
    };
    $.extend(options, customOptions);
    
    if ($.browser.msie || (typeof($.fn.scale) == 'undefined')) {
        // Got IE and want scaling effect? Kiss my ass.
        options.useScaling = false;
    }
    
    var callbackFunction;
    if (typeof(arguments[1]) == 'function') {
        var callbackFunction = arguments[1];
    } else if (typeof(arguments[2] == 'function')) {
        var callbackFunction = arguments[2];
    }

    
    return this.each(function (i) {
        var val;
        var animationQueue = []; // used to store all the animation params before starting the animation; solves initial animation slowdowns
        var $collection = $(collection).clone(); // destination (target) collection
        var $sourceParent = $(this); // source, the visible container of source collection
        var sourceHeight = $(this).css('height'); // used to keep height and document flow during the animation
        
        var destHeight;
        var adjustHeightOnCallback = false;
        
        var offset = $($sourceParent).offset(); // offset of visible container, used in animation calculations
        var offsets = []; // coordinates of every source collection item            
        
        var $source = $(this).find(options.selector); // source collection items
        
        // Replace the collection and quit if IE6
        if ($.browser.msie && $.browser.version.substr(0,1)<7) {
            $sourceParent.html('').append($collection);
            return;
        }

        // Gets called when any animation is finished
        var postCallbackPerformed = 0; // prevents the function from being called more than one time
        var postCallback = function () {
            
            if (!postCallbackPerformed) {
                postCallbackPerformed = 1;
                
                // hack: 
                // used to be: $sourceParent.html($dest.html()); // put target HTML into visible source container
                // but new webkit builds cause flickering when replacing the collections
                $toDelete = $sourceParent.find('> *');
                $sourceParent.prepend($dest.find('> *'));
                $toDelete.remove();
                     
                if (adjustHeightOnCallback) {
                    $sourceParent.css('height', destHeight);
                }
                options.enhancement($sourceParent); // Perform custom visual enhancements on a newly replaced collection
                if (typeof callbackFunction == 'function') {
                    callbackFunction.call(this);
                }                    
            }
        };
        
        // Position: relative situations
        var $correctionParent = $sourceParent.offsetParent();
        var correctionOffset = $correctionParent.offset();
        if ($correctionParent.css('position') == 'relative') {
            if ($correctionParent.get(0).nodeName.toLowerCase() == 'body') {

            } else {
                correctionOffset.top += (parseFloat($correctionParent.css('border-top-width')) || 0);
                correctionOffset.left +=( parseFloat($correctionParent.css('border-left-width')) || 0);
            }
        } else {
            correctionOffset.top -= (parseFloat($correctionParent.css('border-top-width')) || 0);
            correctionOffset.left -= (parseFloat($correctionParent.css('border-left-width')) || 0);
            correctionOffset.top -= (parseFloat($correctionParent.css('margin-top')) || 0);
            correctionOffset.left -= (parseFloat($correctionParent.css('margin-left')) || 0);
        }
        
        // perform custom corrections from options (use when Quicksand fails to detect proper correction)
        if (isNaN(correctionOffset.left)) {
            correctionOffset.left = 0;
        }
        if (isNaN(correctionOffset.top)) {
            correctionOffset.top = 0;
        }
        
        correctionOffset.left -= options.dx;
        correctionOffset.top -= options.dy;

        // keeps nodes after source container, holding their position
        $sourceParent.css('height', $(this).height());
        
        // get positions of source collections
        $source.each(function (i) {
            offsets[i] = $(this).offset();
        });
        
        // stops previous animations on source container
        $(this).stop();
        var dx = 0; var dy = 0;
        $source.each(function (i) {
            $(this).stop(); // stop animation of collection items
            var rawObj = $(this).get(0);
            if (rawObj.style.position == 'absolute') {
                dx = -options.dx;
                dy = -options.dy;
            } else {
                dx = options.dx;
                dy = options.dy;                    
            }

            rawObj.style.position = 'absolute';
            rawObj.style.margin = '0';

            rawObj.style.top = (offsets[i].top - parseFloat(rawObj.style.marginTop) - correctionOffset.top + dy) + 'px';
            rawObj.style.left = (offsets[i].left - parseFloat(rawObj.style.marginLeft) - correctionOffset.left + dx) + 'px';
        });
                
        // create temporary container with destination collection
        var $dest = $($sourceParent).clone();
        var rawDest = $dest.get(0);
        rawDest.innerHTML = '';
        rawDest.setAttribute('id', '');
        rawDest.style.height = 'auto';
        rawDest.style.width = $sourceParent.width() + 'px';
        $dest.append($collection);      
        // insert node into HTML
        // Note that the node is under visible source container in the exactly same position
        // The browser render all the items without showing them (opacity: 0.0)
        // No offset calculations are needed, the browser just extracts position from underlayered destination items
        // and sets animation to destination positions.
        $dest.insertBefore($sourceParent);
        $dest.css('opacity', 0.0);
        rawDest.style.zIndex = -1;
        
        rawDest.style.margin = '0';
        rawDest.style.position = 'absolute';
        rawDest.style.top = offset.top - correctionOffset.top + 'px';
        rawDest.style.left = offset.left - correctionOffset.left + 'px';
        
        

        

        if (options.adjustHeight === 'dynamic') {
            // If destination container has different height than source container
            // the height can be animated, adjusting it to destination height
            $sourceParent.animate({height: $dest.height()}, options.duration, options.easing);
        } else if (options.adjustHeight === 'auto') {
            destHeight = $dest.height();
            if (parseFloat(sourceHeight) < parseFloat(destHeight)) {
                // Adjust the height now so that the items don't move out of the container
                $sourceParent.css('height', destHeight);
            } else {
                //  Adjust later, on callback
                adjustHeightOnCallback = true;
            }
        }
            
        // Now it's time to do shuffling animation
        // First of all, we need to identify same elements within source and destination collections    
        $source.each(function (i) {
            var destElement = [];
            if (typeof(options.attribute) == 'function') {
                
                val = options.attribute($(this));
                $collection.each(function() {
                    if (options.attribute(this) == val) {
                        destElement = $(this);
                        return false;
                    }
                });
            } else {
                destElement = $collection.filter('[' + options.attribute + '=' + $(this).attr(options.attribute) + ']');
            }
            if (destElement.length) {
                // The item is both in source and destination collections
                // It it's under different position, let's move it
                if (!options.useScaling) {
                    animationQueue.push(
                                        {
                                            element: $(this), 
                                            animation: 
                                                {top: destElement.offset().top - correctionOffset.top, 
                                                 left: destElement.offset().left - correctionOffset.left, 
                                                 opacity: 1.0
                                                }
                                        });

                } else {
                    animationQueue.push({
                                        element: $(this), 
                                        animation: {top: destElement.offset().top - correctionOffset.top, 
                                                    left: destElement.offset().left - correctionOffset.left, 
                                                    opacity: 1.0, 
                                                    scale: '1.0'
                                                   }
                                        });

                }
            } else {
                // The item from source collection is not present in destination collections
                // Let's remove it
                if (!options.useScaling) {
                    animationQueue.push({element: $(this), 
                                         animation: {opacity: '0.0'}});
                } else {
                    animationQueue.push({element: $(this), animation: {opacity: '0.0', 
                                     scale: '0.0'}});
                }
            }
        });
        
        $collection.each(function (i) {
            // Grab all items from target collection not present in visible source collection
            
            var sourceElement = [];
            var destElement = [];
            if (typeof(options.attribute) == 'function') {
                val = options.attribute($(this));
                $source.each(function() {
                    if (options.attribute(this) == val) {
                        sourceElement = $(this);
                        return false;
                    }
                });                 

                $collection.each(function() {
                    if (options.attribute(this) == val) {
                        destElement = $(this);
                        return false;
                    }
                });
            } else {
                sourceElement = $source.filter('[' + options.attribute + '=' + $(this).attr(options.attribute) + ']');
                destElement = $collection.filter('[' + options.attribute + '=' + $(this).attr(options.attribute) + ']');
            }
            
            var animationOptions;
            if (sourceElement.length === 0) {
                // No such element in source collection...
                if (!options.useScaling) {
                    animationOptions = {
                        opacity: '1.0'
                    };
                } else {
                    animationOptions = {
                        opacity: '1.0',
                        scale: '1.0'
                    };
                }
                // Let's create it
                d = destElement.clone();
                var rawDestElement = d.get(0);
                rawDestElement.style.position = 'absolute';
                rawDestElement.style.margin = '0';
                rawDestElement.style.top = destElement.offset().top - correctionOffset.top + 'px';
                rawDestElement.style.left = destElement.offset().left - correctionOffset.left + 'px';
                d.css('opacity', 0.0); // IE
                if (options.useScaling) {
                    d.css('transform', 'scale(0.0)');
                }
                d.appendTo($sourceParent);
                
                animationQueue.push({element: $(d), 
                                     animation: animationOptions});
            }
        });
        
        $dest.remove();
        options.enhancement($sourceParent); // Perform custom visual enhancements during the animation
        for (i = 0; i < animationQueue.length; i++) {
            animationQueue[i].element.animate(animationQueue[i].animation, options.duration, options.easing, postCallback);
        }
    });
};
$.fn.sorted = function(customOptions) {
    var options = {
        reversed: false,
        by: function(a) { return a.text(); }
    };
    $.extend(options, customOptions);
    $data = $(this);
    arr = $data.get();
    arr.sort(function(a, b) {
        var valA = options.by($(a));
        var valB = options.by($(b));
        if (options.reversed) {
            return (valA < valB) ? 1 : (valA > valB) ? -1 : 0;				
        } else {		
            return (valA < valB) ? -1 : (valA > valB) ? 1 : 0;	
        }
    });
    return $(arr);
};
})(jQuery);

// DOMContentLoaded
$(function() {
    var $applications = $('#products');
    var $data = $applications.clone();
    $('.sort').click(function(e) {
        $index = $(this).index('.sort');
        var $filteredData = $data.find('.product');
        if ($index == 0) { //sort by price
            var $sortedData = $filteredData.sorted({
                by: function(v) {
                    return parseFloat($(v).find('.amount').text().replace('$',''));
                }
            });
        }else if($index == 1){//sort by date
            return;
        }else if($index == 2){//sort by rating
            var $sortedData = $filteredData.sorted({
                reversed: true,
                by: function(v) {                   
                    return parseFloat($(v).find('.hidden_star').text());
                }
            });
        }
        $applications.quicksand($sortedData, {
            duration: 800,
            easing: 'easeInOutQuad'
        });
    });         
});